﻿using System.Security.Claims;
using System.Text.RegularExpressions;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using StudyCompanion.Commons.Authorize;
using StudyCompanion.Commons.Cache;
using StudyCompanion.Commons.Extension;
using StudyCompanion.Commons.Result;
using StudyCompanion.Core.API;
using StudyCompanion.Dto.User;
using StudyCompanion.Entity.System;
using StudyCompanion.IServices;
using StudyCompanion.Model.User;
using StudyCompanion.Services.CommandHandlers;
using UAParser;

namespace StudyCompanion.WebApi.Controllers;

/// <summary>
///     登录
/// </summary>
[Route("api/[controller]")]
[ApiController]
[AllowAnonymous]
public class LoginController : ApiController
{
    private readonly IMediator _mediator;
    private readonly ICacheService _cacheService;
    private readonly JwtOption _jwtOption;
    private readonly IUserService _userService;

    /// <summary>
    ///     登录
    /// </summary>
    /// <param name="userService"></param>
    /// <param name="cacheService"></param>
    /// <param name="jwtOption"></param>
    /// <param name="mediator"></param>
    public LoginController(IUserService userService
        , ICacheService cacheService
        , IOptions<JwtOption> jwtOption
        , IMediator mediator)
    {
        _userService = userService;
        _jwtOption = jwtOption.Value;
        _cacheService = cacheService;
        _mediator = mediator;
    }

    /// <summary>
    ///     密码登录
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    [HttpPost("PasswordLogin")]
    public async Task<CommonResult<CurrentUserVo>> PasswordLogin(PasswordLoginDto input)
    {
        var response = await _userService.PasswordLogin(input.Account, input.Password);
        if (response.Item1 == null)
        {
            return Problem(response.Item2);
        }

        var user = response.Item1;
        var id = Guid.NewGuid();
        List<Claim> claims = new()
        {
            new Claim(ClaimConst.UserId, response.Item1.Id.ToString()),
            new Claim(ClaimConst.ClientId, id.ToString())
        };
        var result = new CurrentUserVo
        {
            NickName = user.NickName,
            Avatar = user.Avatar,
            Class = user.Class,
            AccessToken = TokenProvider.CreateToken(_jwtOption, claims),
            Identity = user.Identity,
            Phone = user.Phone,
            School = user.School,
            UserId = user.Id,
            ValidTime = user.ValidTime
        };
        var ip = HttpContext.GetClientUserIp();
        var client = Parser.GetDefault().Parse(HttpContext.Request.Headers["User-Agent"]);
        LoginLog log = new()
        {
            UserId = user.Id,
            IPAddress = ip,
            Browser = client.UA.Family + client.UA.Major,
            OS = client.OS.Family + client.OS.Major
        };
        LogInLogCommand logInLogCommand = new()
        {
            LoginLogInputDto = log
        };
        await _mediator.Send(logInLogCommand);
        _cacheService.Add(user.Id.ToString(), id.ToString(), new TimeSpan(12, 0, 0));
        return Success(result);
    }

    /// <summary>
    ///     快速登录
    /// </summary>
    /// <returns></returns>
    [HttpPost("SimpleLogin")]
    public async Task<CommonResult<CurrentUserVo>> SimpleLogin(SimpleLoginDto dto)
    {
        var isPhone = _userService.SimpleLogin(dto);
        if (!isPhone.Item1) return Problem(isPhone.Item2);
        var user = await _userService.GetOrInsertUserByPhone(isPhone.Item2);

        var id = Guid.NewGuid();
        List<Claim> claims = new()
        {
            new Claim(ClaimConst.UserId, user.Id.ToString()),
            new Claim(ClaimConst.ClientId, id.ToString())
        };

        var ip = HttpContext.GetClientUserIp();
        var client = Parser.GetDefault().Parse(HttpContext.Request.Headers["User-Agent"]);
        LoginLog log = new()
        {
            UserId = user.Id,
            IPAddress = ip,
            Browser = client.UA.Family + client.UA.Major,
            OS = client.OS.Family + client.OS.Major
        };
        LogInLogCommand logInLogCommand = new()
        {
            LoginLogInputDto = log
        };
        await _mediator.Send(logInLogCommand);
        _cacheService.Add(user.Id.ToString(), id.ToString(), new TimeSpan(12, 0, 0));

        var result = new CurrentUserVo
        {
            NickName = user.NickName,
            Avatar = user.Avatar,
            Class = user.Class,
            AccessToken = TokenProvider.CreateToken(_jwtOption, claims),
            Identity = user.Identity,
            Phone = user.Phone,
            School = user.School,
            UserId = user.Id,
            ValidTime = user.ValidTime
        };
        return Success(result);
    }

    /// <summary>
    ///     短信验证码登录
    /// </summary>
    /// <param name="dto"></param>
    /// <returns></returns>
    [HttpPost("SmsLongin")]
    public async Task<CommonResult<CurrentUserVo>> SmsLongin(SmsLonginDto dto)
    {
        var code = RedisHelper.Get($"telSMS:{dto.Tel}");
        if (code != dto.Code) return Problem("校验码错误");
        RedisHelper.Del($"telSMS:{dto.Tel}");
        var user = await _userService.GetOrInsertUserByPhone(dto.Tel);
        var id = Guid.NewGuid();
        List<Claim> claims = new()
        {
            new Claim(ClaimConst.UserId, user.Id.ToString()),
            new Claim(ClaimConst.ClientId, id.ToString())
        };
        var result = new CurrentUserVo
        {
            NickName = user.NickName,
            Avatar = user.Avatar,
            Class = user.Class,
            AccessToken = TokenProvider.CreateToken(_jwtOption, claims),
            Identity = user.Identity,
            Phone = user.Phone,
            School = user.School,
            UserId = user.Id,
            ValidTime = user.ValidTime
        };
        var ip = HttpContext.GetClientUserIp();
        var client = Parser.GetDefault().Parse(HttpContext.Request.Headers["User-Agent"]);
        LoginLog log = new()
        {
            UserId = user.Id,
            IPAddress = ip,
            Browser = client.UA.Family + client.UA.Major,
            OS = client.OS.Family + client.OS.Major
        };
        LogInLogCommand logInLogCommand = new()
        {
            LoginLogInputDto = log
        };
        await _mediator.Send(logInLogCommand);
        _cacheService.Add(user.Id.ToString(), id.ToString(), new TimeSpan(12, 0, 0));
        return Success(result);
    }

    /// <summary>
    ///     忘记密码
    /// </summary>
    /// <returns></returns>
    [HttpPost("ForgetPassword")]
    public async Task<CommonResult> ForgetPassword(ForgetPasswordDto dto)
    {
        if (string.IsNullOrEmpty(dto.Tel))
            return Problem("手机号必填");
        const string isTel = @"^1[3456789]\d{9}$"; //手机号正则校验
        if (!Regex.IsMatch(dto.Tel, isTel))
            return Problem("手机号格式错误");
        return await _userService.ForgetPassword(dto);
    }
}